#include <iostream>
#include <cstdlib>
#include <pthread.h>
#include "sock.h"
#include "sockdist.h"
#include <cstdint>
#include <unistd.h>

using namespace std;

struct Interval
{
  uint64_t a;
  uint64_t b;
};

struct ClientStruct
{
  long int nClient;
  int BRCv;
  struct Interval interval;
};

pthread_mutex_t lock_interval = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t lock_nbClients = PTHREAD_MUTEX_INITIALIZER;
long unsigned int nbClients=0;

void * threadClient(void * param)
{
  ClientStruct * desc = (ClientStruct *)param;
  desc->interval.a=0;
  desc->interval.b=0;

  int Rrecv;
  while ((desc->interval.a>=0) && (desc->interval.b>=0))
  {
    Rrecv = recv(desc->BRCv,&(desc->interval),sizeof(struct Interval),0);
    if (Rrecv <=0)
    {
      if (Rrecv == 0) {
	cerr<<"Client déconnecté"<<endl;
	break;
      }
      else //Rrecv < 0
      {
	cerr<<"Erreur dans la réception"<<endl;
	break;
      }
    }
  }

  cout<<"-> Le client "<<desc->nClient<<" s'est déconnecté"<<endl;
  pthread_mutex_lock(&lock_nbClients);
  nbClients--;
  pthread_mutex_unlock(&lock_nbClients);
  delete desc;
  shutdown(desc->BRCv,SHUT_RDWR);
  return NULL;
}

int main(int argc, char *argv[], char *envp[]) {
  int queueLen=20;
  //pthread_t * threads = new pthread_t [queueLen];
  Sock BRPub(SOCK_STREAM,(short)3456,0);
  if (BRPub.good())
  {
    cout<<"# Boîte réseau publique créée"<<endl;
  }
  else
  {
    cerr<<"Erreur lors de la création de la boîte réseau publique"<<endl;
    exit(1);
  }

  if (listen(BRPub.getsDesc(),queueLen))
  {
    cerr<<"Erreur lors de la création de la file d'attente"<<endl;
    perror("Détails ");
    exit(2);
  }
  cout<<"# Attente de connexions"<<endl;
  
  struct sockaddr_in BRCv;
  socklen_t lgBRCv = sizeof(struct sockaddr_in);

  int descBRCv;
  pthread_t thread_id;
  ClientStruct * param;

  while ((descBRCv=accept(BRPub.getsDesc(),(struct sockaddr *)&BRCv,&lgBRCv)))
  {
    if (descBRCv<=0)
    {
      cerr<<"Erreur lors de l'acceptation d'un nouveau client"<<endl;
      exit(3);
    }
    pthread_mutex_lock(&lock_nbClients);
    cout<<"-> Nouveau client connecté ( numéro "<<++nbClients<<") [ boîte : "<<descBRCv<<" ]"<<endl;
    pthread_mutex_unlock(&lock_nbClients);

    param = new ClientStruct; //Deleted in thread
    param->nClient=nbClients;
    param->BRCv=descBRCv;
    
    if (pthread_create( &thread_id , NULL , threadClient, (void*) param))
    {
      cerr<<"Impossible de créer le thread"<<endl;
      exit(4);
    }
    //pthread_join(thread_id, NULL);
    //threadClient(param);
  }
  shutdown(descBRCv,SHUT_RDWR);
  return EXIT_SUCCESS;
}
